home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 5117 < prev    next >
Encoding:
Text File  |  1996-08-06  |  3.6 KB  |  126 lines

  1. Path: news.th-darmstadt.de!news!enno
  2. From: enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: a question about abstract base classes and libraries
  5. Date: 02 Feb 1996 16:33:56 GMT
  6. Organization: Fachbereich Informatik, TH Darmstadt
  7. Distribution: world
  8. Message-ID: <ENNO.96Feb2173356@kitz.inferenzsysteme.informatik.th-darmstadt.de>
  9. References: <4es0b1$au7@news.sdd.hp.com>
  10. NNTP-Posting-Host: kitz.intellektik.informatik.th-darmstadt.de
  11. In-reply-to: Laura Mansfield's message of 2 Feb 1996 03:27:29 GMT
  12.  
  13. In article <4es0b1$au7@news.sdd.hp.com> Laura Mansfield <laura> writes:
  14.  
  15.    A question I'm hoping someone can answer ~
  16.  
  17.    I'm writing a library, lib.a, to be linked to by some client code that
  18.    will use its services.  The client code will include a file, lib.h, which
  19.    defines the class interface to lib.a.  The classes have member functions
  20.    that the client code will use to do some inventory management.
  21.  
  22.    I'd like to hide the private data members of this class, and so have
  23.    decided to create and abstract base class, and make visible to the client
  24.    code only the derived class. To better explain, here's an example:
  25.  
  26.    In my library code:
  27.  
  28.    class Abstract
  29.    {
  30.  
  31.      protected:
  32.  
  33.      int a;
  34.      int b;
  35.  
  36.      public:
  37.  
  38.      virtual void func( void ) = 0;
  39.    };
  40.  
  41.    In lib.h:
  42.  
  43.    class ClassA : public abstract
  44.    {
  45.  
  46.      public:
  47.  
  48.      virtual void func( void );
  49.    };
  50.  
  51.    But I'm beginning to realize I can't really do this w/out defining
  52.    class Abstract in lib.h.  I tried to do "class Abstract;" at the beginning
  53.    of lib.h, but I think this only works for pointers.
  54.  
  55.    Can anyone help me w/ what to do here?
  56.  
  57. When a class should be defined all its base-classes must already be defined.
  58. By reversing your approach, ie. let the clients exclusivly use the interface
  59. not a concrete implementation of the class, you can easily solve the problem.
  60. For example the class representing the interface namely 'Abstract' has to be
  61. public available to all clients and should therefore reside in 'lib.h':
  62.  
  63. class Abstract {
  64.   public:
  65.   virtual ~Abstract() {}
  66.   virtual void func() = 0;
  67. };
  68. <to be continueed>
  69.  
  70. A possible implementation like 'ClassA' goes in 'lib.ph':
  71. #include "lib.h"
  72. class ClassA : public Abstract {
  73.  public:
  74.   void func();
  75. };
  76.  
  77. and its implementation in 'lib.C':
  78. #include "lib.ph"
  79. void ClassA :: func() { /* - here goes the implementation - */ }
  80. <to be continueed>
  81.  
  82. Clients must not use 'lib.ph' directly. They use 'lib.h' instead and don't
  83. care about a particular implementation. The problem that remains for a client
  84. is howto create an instance of a subclass of 'Abstract' without knowing what
  85. the subclass looks like.
  86. A commonly accepted solution is a so-called 'factory-class'. It provides a
  87. method for creating an instance of a specific implementation but returns
  88. a pointer to the underlying interface. For example:
  89.  
  90. 'lib.h':
  91. ...
  92. typedef Abstract* (*ACF)();
  93. class AFactory {
  94.  public:
  95.   static void Set(ACF);
  96.   static Abstract* CreateA();
  97.  
  98.  private:
  99.   static ACF acf_;
  100. };
  101.   
  102. 'lib.C':
  103. ... 
  104. void AFactory :: Set(ACF acf) { acf_=acf; }
  105. Abstract* AFactory :: CreateA() { return acf_ ? (*acf_)() : new ClientA(); }
  106. ACF AFactory :: acf_=0;
  107.  
  108. A client uses the factory to create the appropriate instances:
  109.  
  110. client.C:
  111. #include "lib.h"
  112.  
  113. void f()
  114. {
  115.   Abstract* a=AFactory :: CreateA();
  116.    ...
  117. }
  118.  
  119. The standard-behavior for creating instances simply returns an instance of
  120. 'ClientA'. You can easily modify this behavior with the 'Set' method of
  121. 'AFactory'. There are other solutions to the problem of the instance-creation.
  122. Several nifty solutions are described in 'Design Patterns' book from E. Gamma,
  123. R. Helm, R. Johnson and J. Vlissides.
  124.  
  125.     Enno
  126.